package br.com.iswe.gwt.crud.client;

import br.com.iswe.core.entidades.gwt.BeanMap;
import br.com.iswe.core.entidades.gwt.RemoteEntityObject;
import br.com.iswe.gwt.ui.client.DomainFormFactory;
import br.com.iswe.gwt.ui.client.Listener;
import br.com.iswe.gwt.ui.client.ListenerCollection;
import br.com.iswe.gwt.ui.client.MessagePanel;
import br.com.iswe.gwt.ui.client.PopupValidationHandler;
import br.com.iswe.gwt.ui.client.QueryInfo;
import br.com.iswe.gwt.ui.client.RequestInfo;
import br.com.iswe.gwt.ui.client.ValidationHandlerImpl;
import br.com.iswe.gwt.ui.client.service.CrudServiceClientImpl;
import br.com.iswe.gwt.ui.client.service.ServiceClientAbstract;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FocusWidget;

public abstract class CrudDetailPanel<E extends RemoteEntityObject> extends DetailsPanelAbstract<E> implements DetailPanelContract<E> {
	
	protected static final String PROPERTY = "property";
	
	public CrudDetailPanel(){}
	
	protected DomainFormFactory<E> formFactory = new DomainFormFactory<E>(new PopupValidationHandler(), new ValidationHandlerImpl());
	public DomainFormFactory<E> getFormFactory() {
		return formFactory;
	}

	protected abstract String getIdProperty();
	protected abstract CrudServiceClientImpl<E> getService();
	protected abstract void setupScreen();
	protected abstract QueryInfo getQueryInfoDetail();
	protected abstract RequestInfo getRequestInfoSave();
	
	protected void populate(E entity){
		formFactory.populateFormProperties(entity);
	}
	
	private ListenerCollection<DetailPanelContract<E>> cancelListener = new ListenerCollection<DetailPanelContract<E>>();
	private ListenerCollection<DetailPanelContract<E>> afterSaveListener = new ListenerCollection<DetailPanelContract<E>>();
	private ListenerCollection<DetailPanelContract<E>> afterDeleteListener = new ListenerCollection<DetailPanelContract<E>>();
	private ListenerCollection<DetailPanelContract<E>> afterDetailListener = new ListenerCollection<DetailPanelContract<E>>();
	
	protected void cancelClose() {
		cancelListener.fire(this);
	}
	
	protected void afterDetail() {
		afterDetailListener.fire(this);
	}
	
	protected void errorOnSave(Throwable caught) {
		MessagePanel.getInstance().showError(caught, "Error saving the record!");
		if(getSaveButton() != null){
			getSaveButton().setEnabled(true);
		}
	}
	
	protected void afterSave(E entity) {
		//popula o formFactory com os dados modificados
		populate(entity);
		//show the success message
		MessagePanel.getInstance().showMessage("Record saved successfully !");
		//
		if(getSaveButton() != null){
			getSaveButton().setEnabled(true);
		}
		//
		afterSaveListener.fire(this);
	}
	
	protected E beforeSave() {
		E entity = null; // formFactory.getMapValues();
		if(getSaveButton() != null){
			getSaveButton().setEnabled(false);
		}
		return entity;
	}
	
	
	
	protected void notValidOnSave(){
		if(getSaveButton() != null){
			getSaveButton().setEnabled(true);
		}
	}
	
	protected void delete(){
		E entity = beforeDelete();		
		getService().delete(entity, new AsyncCallback<Boolean>(){
			public void onFailure(Throwable caught) {
				errorOnDelete(caught);
			}
			public void onSuccess(Boolean result) {
				afterDelete();
			}
		});
	}
	
	protected abstract E beforeDelete();
	
	protected void afterDelete() {
		MessagePanel.getInstance().showMessage("Record deleted successfully !");
		if(getDeleteButton() != null){
			getDeleteButton().setEnabled(true);
		}
		afterDeleteListener.fire(this);
	}
	
	protected void errorOnDelete(Throwable caught) {
		MessagePanel.getInstance().showError(caught, "Error deleting the record!");
		if(getDeleteButton() != null){
			getDeleteButton().setEnabled(true);
		}
	}

	protected void save(){
		E entity = beforeSave();
		
		if( ! validate() ){
			notValidOnSave();
			return;
		}
		
		getService().save(entity, new AsyncCallback<E>(){
			public void onFailure(Throwable caught) {
				errorOnSave(caught);
			}
			public void onSuccess(E savedEntity) {
				afterSave(savedEntity);
			}}, 
			getRequestInfoSave());
	}
	
	protected boolean validate(){
		return formFactory.validate();
	}


	@SuppressWarnings("unchecked")
	protected void removerManyToMany(BeanMap bean, QueryInfo queryInfo) {
		getService().removerManyToMany(bean, queryInfo, new AsyncCallback<E>(){
			public void onFailure(Throwable caught) {
				MessagePanel.getInstance().showError(caught, "Error removing selected itens!");
			}
			public void onSuccess(E bean) {
				//popula a tela de usuario com a lista q foi salva
				//popula com a nova versao da entidade
				populate(bean);
			}});
	}
	
	@SuppressWarnings("unchecked")
	protected void showSearchPanelAsPopup(SearchPanel searchPanel, QueryInfo queryInfoDetailList, BeanMap bean, ServiceClientAbstract<E> manyToManyService, String title) {
		super.showSearchPanelAsPopup(searchPanel, queryInfoDetailList, bean, manyToManyService, title, new AsyncCallback<E>() {
			public void onSuccess(E entity) {
				populate(entity);
			}
			public void onFailure(Throwable caught) {
				MessagePanel.getInstance().showError(caught, "Error saving selected itens!");
			}
		});
	}
	
	protected abstract E beforeDetail(E entity);
	
	public void detail(E entity) {
		//Detalha o registro
		//cria um novo mapa contendo apenas o id da entidade
		E filter = beforeDetail(entity);
		
		getService().detail(filter, getQueryInfoDetail(), new AsyncCallback<E>(){
			public void onFailure(Throwable caught) {
				MessagePanel.getInstance().showError(caught, "Error detail the record!");
			}
			public void onSuccess(E result) {
				//popula o formFactory com os dados m
				populate(result);
				afterDetail();
			}});
	}
	
	
	public void addAfterDetailListener(Listener<DetailPanelContract<E>> listener){
		afterDetailListener.add(listener);
	}
	
	public void addCancelListener(Listener<DetailPanelContract<E>> listener){
		cancelListener.add(listener);
	}
	
	public void addAfterSaveListener(Listener<DetailPanelContract<E>> listener){
		afterSaveListener.add(listener);
	}
	
	public void addAfterDeleteListener(Listener<DetailPanelContract<E>> listener){
		afterDeleteListener.add(listener);
	}

	public E getEntity(){
		return null;// getFormFactory().getMapValues();
	}

	protected FocusWidget getSaveButton(){return null;}
	
	protected FocusWidget getDeleteButton(){return null;}
	
	public void prepareInsert(){
		if(getDeleteButton() != null){
			getDeleteButton().setEnabled(false);
		}
	}
}
